﻿using Common.Communication;
using Common.Device.DeviceDb;
using Common.Device.Enums;
using Common.Device.Interfaces;
using Common.Tool.DataTools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Channels;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Documents;

namespace DianZiFuZai
{
    public class IT8511SerialPort : SerialPortBase,IDianZiFuZai
    {
        public string Name { get ; set; }
        byte Addr;
        public IT8511SerialPort(UseDevice device) : base(device.port, Convert.ToInt32(device.parameter), timeout: 1500)
        {
            Name = device.name;
            Addr = Convert.ToByte(device.addr);
        }
        public Result<double> ReadCurrentValue(DianZiFuZaiEnum.DianZiFuZaiMode mode)
        {
            lock (this)
            {
                var result = new Result<double>();
                var write = new Result<byte[]>();
                var read = new Result<byte[]>();
                AppendInfo(Name, $"读取当前负载值");
                var command = CmdSetControlMode(true);
                write = WriteThenRead(command, wait: 100);
                var want = CmdSetOk;
                if (!write.IsSucceed || !write.Value.Take(want.Length).SequenceEqual(want))
                {
                    result.IsSucceed = false;
                    result.Err = "设置远端通信失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                Thread.Sleep(100);
                command = CmdReadCurrentValue();
                read = WriteThenRead(command, wait: 100);
                want = CmdReadCurrentValueOk;
                if (!read.IsSucceed || !read.Value.Take(want.Length).SequenceEqual(want))
                {
                    result.IsSucceed = false;
                    result.Err = "读取当前负载值失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.电压)
                {
                    result.Value = ((read.Value[6] << 24) + (read.Value[5] << 16) + (read.Value[4] << 8) + read.Value[3]) / 1000.0f;
                    AppendResult(Name, DataConvert.ToUnit(result.Value, "F3") + "V");
                }
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.电流)
                {
                    result.Value = ((read.Value[10] << 24) + (read.Value[9] << 16) + (read.Value[8] << 8) + read.Value[7]) / 10000.0f;
                    AppendResult(Name, DataConvert.ToUnit(result.Value, "F3") + "A");
                }
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.功率)
                {
                    result.Value = ((read.Value[14] << 24) + (read.Value[13] << 16) + (read.Value[12] << 8) + read.Value[11]) / 1000.0f;
                    AppendResult(Name, DataConvert.ToUnit(result.Value, "F3") + "W");
                }
                return result.EndTime();
            }
        }

        public Result<double> ReadSetValue(DianZiFuZaiEnum.DianZiFuZaiMode mode)
        {
            lock (this)
            {
                var result = new Result<double>();
                var write = new Result<byte[]>();
                var read = new Result<byte[]>();
                AppendInfo(Name, $"读取设置负载值");
                var command = CmdSetControlMode(true);
                write = WriteThenRead(command);
                var want = CmdSetOk;
                if (!write.IsSucceed || !write.Value.Take(want.Length).SequenceEqual(want))
                {
                    result.IsSucceed = false;
                    result.Err = "设置远端通信失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                Thread.Sleep(100);
                command = CmdReadFuZaiValue(mode);
                read = WriteThenRead(command, wait: 100);
                want = CmdReadFuZaiValueOk(mode);
                if (!read.IsSucceed || !read.Value.Take(want.Length).SequenceEqual(want))
                {
                    result.IsSucceed = false;
                    result.Err = "读取设置负载值失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                result.Value = ((read.Value[6] << 24) + (read.Value[5] << 16) + (read.Value[4] << 8) + read.Value[3]);
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.电压)
                {
                    result.Value = result.Value / 1000.0f;
                    AppendResult(Name, DataConvert.ToUnit(result.Value, "F3") + "V");
                }
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.电流)
                {
                    result.Value = result.Value / 10000.0f;
                    AppendResult(Name, DataConvert.ToUnit(result.Value, "F3") + "A");
                }
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.功率)
                {
                    result.Value = result.Value / 1000.0f;
                    AppendResult(Name, DataConvert.ToUnit(result.Value, "F3") + "W");
                }
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.电阻)
                {
                    result.Value = result.Value / 1000.0f;
                    AppendResult(Name, DataConvert.ToUnit(result.Value, "F3") + "Ω");
                }
                return result.EndTime();
            }
        }

        public Result<bool> SetOn(DianZiFuZaiEnum.DianZiFuZaiMode mode, double value)
        {
            lock (this)
            {
                var result = new Result<bool>();
                var write = new Result<byte[]>();
                var read = new Result<byte[]>();
                AppendInfo(Name, $"设置负载模式{mode.ToString()}");
                var command = CmdSetControlMode(true);
                write = WriteThenRead(command, wait: 100);
                var want = CmdSetOk;
                if (!write.IsSucceed || !write.Value.Take(want.Length).SequenceEqual(want))
                {
                    result.IsSucceed = false;
                    result.Err = "设置远端通信失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                command = CmdSetFuZaiMode(mode);
                write = WriteThenRead(command, wait: 100);
                if (!write.IsSucceed || !write.Value.Take(CmdSetOk.Length).SequenceEqual(CmdSetOk))
                {
                    result.IsSucceed = false;
                    result.Err = "设置负载模式失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                Thread.Sleep(100);
                command = CmdReadFuZaiMode();
                read = WriteThenRead(command, wait: 100);
                want = CmdReadFuZaiModeOk(mode);
                if (!read.IsSucceed || !read.Value.Take(want.Length).SequenceEqual(want))
                {
                    result.IsSucceed = false;
                    result.Err = "读取设置负载模式失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                AppendInfo(Name, $"设置负载定值{value}");
                command = CmdSetFuZaiValue(mode, value);
                write = WriteThenRead(command, wait: 100);
                if (!write.IsSucceed || !write.Value.Take(CmdSetOk.Length).SequenceEqual(CmdSetOk))
                {
                    result.IsSucceed = false;
                    result.Err = "设置负载定值失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                Thread.Sleep(100);
                command = CmdReadFuZaiValue(mode);
                read = WriteThenRead(command, wait: 100);
                want = CmdReadFuZaiValueOk(mode);
                if (!read.IsSucceed || !read.Value.Take(want.Length).SequenceEqual(want))
                {
                    result.IsSucceed = false;
                    result.Err = "读取设置负载定值失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                double set = ((read.Value[6] << 24) + (read.Value[5] << 16) + (read.Value[4] << 8) + read.Value[3]);
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.电压)
                {
                    set = set / 1000.0f;
                    AppendResult(Name, DataConvert.ToUnit(set, "F3") + "V");
                }
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.电流)
                {
                    set = set / 10000.0f;
                    AppendResult(Name, DataConvert.ToUnit(set ,"F3") + "A");
                }
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.功率)
                {
                    set = set / 1000.0f;
                    AppendResult(Name, DataConvert.ToUnit(set, "F3") + "W");
                }
                if (mode == DianZiFuZaiEnum.DianZiFuZaiMode.电阻)
                {
                    set = set / 1000.0f;
                    AppendResult(Name, DataConvert.ToUnit(set, "F3") + "Ω");
                }
                if (set != value)
                {
                    result.IsSucceed = false;
                    result.Err = "设置负载定值失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                Thread.Sleep(500);
                AppendInfo(Name, $"设置负载状态ON");
                command = CmdSetStatus(true);
                write = WriteThenRead(command, wait: 100);
                if (!write.IsSucceed || !write.Value.Take(CmdSetOk.Length).SequenceEqual(CmdSetOk))
                {
                    result.IsSucceed = false;
                    result.Err = "设置负载状态失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                return result.EndTime();
            }
        }

        public Result<bool> SetOff()
        {
            lock (this)
            {
                var result = new Result<bool>();
                var write = new Result<byte[]>();
                var read = new Result<byte[]>();
                AppendInfo(Name, $"设置负载状态OFF");
                var command = CmdSetControlMode(true);
                write = WriteThenRead(command, wait: 100);
                var want = CmdSetOk;
                if (!write.IsSucceed || !write.Value.Take(want.Length).SequenceEqual(want))
                {
                    result.IsSucceed = false;
                    result.Err = "设置远端通信失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                Thread.Sleep(500);
                command = CmdSetStatus(false);
                write = WriteThenRead(command, wait: 100);
                if (!write.IsSucceed || !write.Value.Take(CmdSetOk.Length).SequenceEqual(CmdSetOk))
                {
                    result.IsSucceed = false;
                    result.Err = "设置负载状态失败";
                    AppendTip(Name, result.Err);
                    return result.EndTime();
                }
                return result.EndTime();
            }
        }

        public double VolMin = 0;
        public double VolMax = 120.000f;
        public double CurMin = 0;
        public double CurMax = 20.0000f;
        public double WattMin = 0;
        public double WattMax = 120.000f;
        public double RMin = 0;
        public double RMax = 4000.000f;

        byte[] CmdSetControlMode(bool remote)
        {
            byte remoteByte = Convert.ToByte(remote == true ? 0x01 : 0x00);
            byte[] order = new byte[25] { 0xAA, Addr, 0x20, remoteByte,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00 , 0x00 };
            return ByteHelper.GetSumCcBytes(order);
        }
        byte[] CmdSetStatus(bool enable)
        {
            byte enableByte = Convert.ToByte(enable == true ? 0x01 : 0x00);
            byte[] order = new byte[25] { 0xAA, Addr, 0x21, enableByte,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00 , 0x00 };
            return ByteHelper.GetSumCcBytes(order);
        }
        byte[] CmdSetOk => new byte[4] { 0xAA, Addr, 0x12, 0x80 };
        
        byte[] CmdSetMaxInput(DianZiFuZaiEnum.DianZiFuZaiMode mode, double value)
        {
            byte modeByte = 0x22;
            int maxValue = 0;
            switch (mode)
            {
                case DianZiFuZaiEnum.DianZiFuZaiMode.电压: modeByte = 0x22; maxValue = Convert.ToInt32(value * 1000); break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电流: modeByte = 0x24; maxValue = Convert.ToInt32(value * 10000); break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.功率: modeByte = 0x26; maxValue = Convert.ToInt32(value * 1000); break;
                default:
                    break;
            }
            byte low1 = Convert.ToByte(maxValue & 0xff);
            byte low2 = Convert.ToByte((maxValue >> 8) & 0xff);
            byte high1 = Convert.ToByte((maxValue >> 16) & 0xff);
            byte high2 = Convert.ToByte((maxValue >> 24) & 0xff);
            byte[] order = new byte[25] { 0xAA, Addr, modeByte,low1,low2,high1,high2,
               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00 , 0x00 };
            return ByteHelper.GetSumCcBytes(order);
        }
        byte[] CmdReadMaxInput(DianZiFuZaiEnum.DianZiFuZaiMode mode)
        {
            byte modeByte = 0x23;
            switch (mode)
            {
                case DianZiFuZaiEnum.DianZiFuZaiMode.电压: modeByte = 0x23; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电流: modeByte = 0x25; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.功率: modeByte = 0x27; break;
                default:
                    break;
            }
            byte[] order = new byte[25] { 0xAA, Addr, modeByte,0x00, 0x00, 0x00, 0x00,
               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00 , 0x00 };
            return ByteHelper.GetSumCcBytes(order);
        }
        byte[] CmdReadMaxInputOk(DianZiFuZaiEnum.DianZiFuZaiMode mode, double value)
        {
            byte modeByte = 0x23;
            int maxValue = 0;
            switch (mode)
            {
                case DianZiFuZaiEnum.DianZiFuZaiMode.电压: modeByte = 0x23; maxValue = Convert.ToInt32(value * 1000); break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电流: modeByte = 0x25; maxValue = Convert.ToInt32(value * 10000); break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.功率: modeByte = 0x27; maxValue = Convert.ToInt32(value * 1000); break;
                default:
                    break;
            }
            byte low1 = Convert.ToByte(maxValue & 0xff);
            byte low2 = Convert.ToByte((maxValue >> 8) & 0xff);
            byte high1 = Convert.ToByte((maxValue >> 16) & 0xff);
            byte high2 = Convert.ToByte((maxValue >> 24) & 0xff);
            byte[] order = new byte[7] { 0xAA, Addr, modeByte, low1, low2, high1, high2 };
            return order;
        }
        byte[] CmdSetFuZaiValue(DianZiFuZaiEnum.DianZiFuZaiMode mode, double value)
        {
            byte modeByte = 0x2A;
            int setValue = 0;
            switch (mode)
            {
                case DianZiFuZaiEnum.DianZiFuZaiMode.电压: modeByte = 0x2C; setValue = Convert.ToInt32(value * 1000); break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电流: modeByte = 0x2A; setValue = Convert.ToInt32(value * 10000); break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.功率: modeByte = 0x2E; setValue = Convert.ToInt32(value * 1000); break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电阻: modeByte = 0x30; setValue = Convert.ToInt32(value * 1000); break;
                default:
                    break;
            }
            byte low1 = Convert.ToByte(setValue & 0xff);
            byte low2 = Convert.ToByte((setValue >> 8) & 0xff);
            byte high1 = Convert.ToByte((setValue >> 16) & 0xff);
            byte high2 = Convert.ToByte((setValue >> 24) & 0xff);
            byte[] order = new byte[25] { 0xAA, Addr, modeByte,low1,low2,high1,high2,
               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00 , 0x00 };
            return ByteHelper.GetSumCcBytes(order);
        }
        byte[] CmdReadFuZaiValue(DianZiFuZaiEnum.DianZiFuZaiMode mode)
        {
            byte modeByte = 0x2B;
            switch (mode)
            {
                case DianZiFuZaiEnum.DianZiFuZaiMode.电压: modeByte = 0x2D; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电流: modeByte = 0x2B; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.功率: modeByte = 0x2F; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电阻: modeByte = 0x31; break;
                default:
                    break;
            }
            byte[] order = new byte[25] { 0xAA, Addr, modeByte,0x00, 0x00, 0x00, 0x00,
               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00 , 0x00 };
            return ByteHelper.GetSumCcBytes(order);
        }
        byte[] CmdReadFuZaiValueOk(DianZiFuZaiEnum.DianZiFuZaiMode mode)
        {
            byte modeByte = 0x2B;
            switch (mode)
            {
                case DianZiFuZaiEnum.DianZiFuZaiMode.电压: modeByte = 0x2D;  break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电流: modeByte = 0x2B;  break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.功率: modeByte = 0x2F;  break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电阻: modeByte = 0x31;  break;
                default:
                    break;
            }
            byte[] order = new byte[3] { 0xAA, Addr, modeByte};
            return order;
        }
        byte[] CmdSetFuZaiMode(DianZiFuZaiEnum.DianZiFuZaiMode mode)
        {
            byte modeByte = 0x28;
            byte type = 0x01;
            switch (mode)
            {
                case DianZiFuZaiEnum.DianZiFuZaiMode.电压: type = 0x01; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电流: type = 0x00; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.功率: type = 0x02; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电阻: type = 0x03; break;
                default:
                    break;
            }
            byte[] order = new byte[25] { 0xAA, Addr, modeByte,type,0x00, 0x00, 0x00,
               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00 , 0x00 };
            return ByteHelper.GetSumCcBytes(order);
        }
        byte[] CmdReadFuZaiMode()
        {
            byte typeByte = 0x29;
            byte[] order = new byte[25] { 0xAA, Addr, typeByte,0x00, 0x00, 0x00, 0x00,
               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00 , 0x00 };
            return ByteHelper.GetSumCcBytes(order);
        }
        byte[] CmdReadFuZaiModeOk(DianZiFuZaiEnum.DianZiFuZaiMode mode)
        {
            byte modeByte = 0x29;
            byte type = 0x01;
            switch (mode)
            {
                case DianZiFuZaiEnum.DianZiFuZaiMode.电压: type = 0x01; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电流: type = 0x00; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.功率: type = 0x02; break;
                case DianZiFuZaiEnum.DianZiFuZaiMode.电阻: type = 0x03; break;
                default:
                    break;
            }
            byte[] order = new byte[4] { 0xAA, Addr, modeByte, type };
            return order;
        }
        byte[] CmdReadCurrentValue()
        {
            byte[] order = new byte[25] { 0xAA, Addr, 0x5F,0x00,0x00,0x00,0x00,
               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00 , 0x00 };
            return ByteHelper.GetSumCcBytes(order);
        }
        byte[] CmdReadCurrentValueOk => new byte[3] { 0xAA, Addr, 0x5F };
    }
}
